#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
文件名称: cache_manager.py
完整路径: backend/services/cache_manager.py
功能说明:
    聚合数据缓存管理服务
    支持报表和图表页面之间的数据传递，避免重复查询
"""

import json
import time
import uuid
import hashlib
from typing import Optional, Dict, Any
from flask import current_app

try:
    import redis
    REDIS_AVAILABLE = True
except ImportError:
    REDIS_AVAILABLE = False


class AggregatedDataCache:
    """聚合数据缓存管理器"""
    
    def __init__(self):
        self.redis_client = None
        self.memory_cache = {}  # 备用内存缓存
        self._initialized = False
        
    def _ensure_initialized(self):
        """延迟初始化，确保在Flask应用上下文中"""
        if self._initialized:
            return
            
        if not REDIS_AVAILABLE:
            try:
                from flask import current_app
                current_app.logger.warning("Redis不可用，使用内存缓存")
            except RuntimeError:
                # 如果没有应用上下文，静默处理
                pass
            self._initialized = True
            return
        
        try:
            from flask import current_app
            from backend.config.constants_v2 import SYSTEM_CONFIG
            redis_config = SYSTEM_CONFIG.get("REDIS_CONFIG", {})
            
            self.redis_client = redis.Redis(
                host=redis_config.get("host", "localhost"),
                port=redis_config.get("port", 6379),
                db=redis_config.get("db", 0),
                decode_responses=True
            )
            
            # 测试连接
            self.redis_client.ping()
            current_app.logger.info("Redis缓存连接成功")
            
        except Exception as e:
            try:
                from flask import current_app
                current_app.logger.warning(f"Redis连接失败，使用内存缓存: {e}")
            except RuntimeError:
                # 如果没有应用上下文，静默处理
                pass
            self.redis_client = None
            
        self._initialized = True
    
    def _generate_cache_key(self, user_id: int, source_type: str) -> str:
        """生成安全的缓存键"""
        timestamp = str(int(time.time()))
        unique_id = str(uuid.uuid4())[:8]
        
        return f"agg_data_{user_id}_{source_type}_{timestamp}_{unique_id}"
    
    def _get_user_cache_pattern(self, user_id: int, source_type: str = None) -> str:
        """获取用户缓存匹配模式"""
        if source_type:
            return f"agg_data_{user_id}_{source_type}_*"
        return f"agg_data_{user_id}_*"
    
    def store_data(self, user_id: int, aggregated_data: Dict[str, Any], 
                   source_type: str = 'report') -> Optional[str]:
        """
        存储聚合数据
        
        Args:
            user_id: 用户ID
            aggregated_data: 聚合数据
            source_type: 数据来源类型 ('report' 或 'chart')
            
        Returns:
            缓存键，失败时返回None
        """
        self._ensure_initialized()
        
        try:
            current_app.logger.info(f"🔍 开始存储缓存数据 - 用户ID: {user_id}, 来源: {source_type}")
            
            # 清除该用户的旧缓存
            self._cleanup_user_cache_by_type(user_id, source_type)
            
            # 生成新的缓存键
            cache_key = self._generate_cache_key(user_id, source_type)
            current_app.logger.info(f"📝 生成缓存键: {cache_key}")
            
            # 准备缓存数据
            cache_data = {
                'data': aggregated_data,
                'source': source_type,
                'created_at': int(time.time()),
                'user_id': user_id
            }
            
            current_app.logger.info(f"📦 准备缓存数据，数据大小: {len(str(cache_data))} 字符")
            
            # 存储数据
            if self.redis_client:
                # 使用Redis存储，过期时间10分钟
                current_app.logger.info("🔴 使用Redis存储缓存")
                self.redis_client.setex(cache_key, 600, json.dumps(cache_data))
            else:
                # 使用内存缓存
                current_app.logger.info("🟠 使用内存缓存存储")
                self.memory_cache[cache_key] = {
                    'data': cache_data,
                    'expires_at': time.time() + 600
                }
            
            current_app.logger.info(f"✅ 缓存数据存储成功: {cache_key}")
            return cache_key
            
        except Exception as e:
            current_app.logger.error(f"缓存数据存储失败: {e}")
            return None
    
    def get_and_refresh(self, cache_key: str, user_id: int) -> Optional[Dict[str, Any]]:
        """
        获取缓存数据并刷新过期时间
        
        Args:
            cache_key: 缓存键
            user_id: 用户ID（用于权限验证）
            
        Returns:
            聚合数据，失败时返回None
        """
        self._ensure_initialized()
        
        try:
            # 验证缓存键格式
            if not cache_key.startswith(f"agg_data_{user_id}_"):
                current_app.logger.warning(f"用户{user_id}尝试访问无权限的缓存: {cache_key}")
                return None
            
            # 获取数据
            if self.redis_client:
                data_str = self.redis_client.get(cache_key)
                if data_str:
                    cache_data = json.loads(data_str)
                    
                    # 验证用户权限
                    if cache_data.get('user_id') != user_id:
                        current_app.logger.warning(f"缓存数据用户ID不匹配: {cache_key}")
                        return None
                    
                    # 刷新过期时间（延长5分钟）
                    self.redis_client.expire(cache_key, 300)
                    
                    current_app.logger.info(f"缓存数据获取成功: {cache_key}")
                    return cache_data['data']
            else:
                # 内存缓存
                cache_item = self.memory_cache.get(cache_key)
                if cache_item and cache_item['expires_at'] > time.time():
                    cache_data = cache_item['data']
                    
                    if cache_data.get('user_id') != user_id:
                        return None
                    
                    # 刷新过期时间
                    cache_item['expires_at'] = time.time() + 300
                    return cache_data['data']
            
            return None
            
        except Exception as e:
            current_app.logger.error(f"缓存数据获取失败: {e}")
            return None
    
    def _cleanup_user_cache_by_type(self, user_id: int, source_type: str):
        """清理指定用户指定类型的缓存"""
        try:
            pattern = self._get_user_cache_pattern(user_id, source_type)
            
            if self.redis_client:
                keys = list(self.redis_client.scan_iter(match=pattern))
                if keys:
                    self.redis_client.delete(*keys)
                    current_app.logger.info(f"清理用户{user_id}的{source_type}类型缓存: {len(keys)}个")
            else:
                # 内存缓存清理
                keys_to_delete = [k for k in self.memory_cache.keys() if k.startswith(f"agg_data_{user_id}_{source_type}_")]
                for key in keys_to_delete:
                    del self.memory_cache[key]
                    
        except Exception as e:
            current_app.logger.error(f"缓存清理失败: {e}")
    
    def cleanup_user_cache(self, user_id: int):
        """清理指定用户的所有缓存"""
        try:
            pattern = self._get_user_cache_pattern(user_id)
            
            if self.redis_client:
                keys = list(self.redis_client.scan_iter(match=pattern))
                if keys:
                    self.redis_client.delete(*keys)
                    current_app.logger.info(f"清理用户{user_id}的所有缓存: {len(keys)}个")
            else:
                keys_to_delete = [k for k in self.memory_cache.keys() if k.startswith(f"agg_data_{user_id}_")]
                for key in keys_to_delete:
                    del self.memory_cache[key]
                    
        except Exception as e:
            current_app.logger.error(f"用户缓存清理失败: {e}")
    
    def cleanup_expired_cache(self):
        """清理过期的内存缓存（仅内存缓存需要）"""
        self._ensure_initialized()
        
        if not self.redis_client:
            current_time = time.time()
            expired_keys = [k for k, v in self.memory_cache.items() 
                          if v['expires_at'] <= current_time]
            for key in expired_keys:
                del self.memory_cache[key]


# 全局缓存管理器实例
cache_manager = AggregatedDataCache()
